(* Creme Caramel Compiler (Triple C) - Michele Caceffo - 2008 *)

open Exceptions;;
open Syntaxtree;;
open Print_syntaxtree;;
open Intermediate;;
open Declaration;;
open Expressions;;
open Semantic;;
open Commands;;
open Subroutines;;
open Target;;
open Print;;
open Lexer;;
open Lexing;;
open Parser;;

(** This is the main function of the compiler, which s formed by five phases:
    1-Generation of the Abstract Syntax Tree (with file output)
    2-Generation of the Declarations Table
    3-Generation of the Procedure Table
    4-Generation of the Intermediate Code (with file output)
    5-Generation of the Target Code (with file output)
*)
let lexbuf = Lexing.from_channel stdin and
flaglist = [Open_creat;Open_trunc;Open_wronly] and
outdir = "./output/" and
perm = 0o777 in (
    print_string ">>> Reading input file and processing syntactic analisys...\n";
    let syntaxtree = try program lex lexbuf with _ -> SynError in (
        match syntaxtree with
            Program(decl,procl,comd) -> (
                let synout = open_out_gen flaglist perm (outdir^"syntax.ast") in print_program syntaxtree (synout);
                print_string ">>> The program is syntactically correct!\n";
                let ic = new intermediateCode in
                    let dect = (genDecTable decl (Hashtbl.create 0) ic false) in
                        let proct = (genSubTable procl dect (Hashtbl.create 0) ic) in (
                            print_string ">>> Starting semantic analisys...\n";
                         (*   if(cmdsemantic comd dect proct) then (   *)
                                print_string ">>> The program is semantically correct!\n";
                                print_string ">>> Begin compilation...\n";
                                genCommand comd dect proct ic;
                                ic#addInstr (HALT, Null, Null, Null);
                                let streamout = open_out_gen flaglist perm (outdir^"code.ic") and
                                cout = open_out_gen flaglist perm (outdir^"code.c") in
                                    print_ICode (streamout) (ic#getInstructionList);
                                    print_string ">>> The IC CODE is generated!\n";
                                    output_string (cout) Target.header;
                                    print_DecTable (cout) (dect);
                                    c_subroutines (cout) (proct) (ic);
                                    output_string (cout) (Target.main_start (Hashtbl.length dect));
                                    c_generator (ic#getInstructionList) (ic) (cout) 0 proct;
                                    output_string (cout) Target.main_end;
                                    print_string ">>> The C CODE is generated!\n";
                           (* ) else (
                                print_string ">>> The program is not semantically correct!\n"
                            *)
                        )
                )
            | SynError -> print_string ("Syntax error at line " ^ (string_of_int (lexbuf.lex_start_p.pos_lnum)) ^ "\n")
    )
)
